package org.xxpay.manage.order.ctrl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.xxpay.core.common.annotation.MethodLog;
import org.xxpay.core.common.constant.Constant;
import org.xxpay.core.common.constant.MchConstant;
import org.xxpay.core.common.constant.PayConstant;
import org.xxpay.core.common.constant.RetEnum;
import org.xxpay.core.common.domain.BizResponse;
import org.xxpay.core.common.domain.XxPayPageRes;
import org.xxpay.core.common.domain.XxPayResponse;
import org.xxpay.core.common.domain.api.msg.QueryRetMsg;
import org.xxpay.core.common.util.AmountUtil;
import org.xxpay.core.common.util.DateUtil;
import org.xxpay.core.common.util.MyLog;
import org.xxpay.core.entity.PayOrder;
import org.xxpay.core.entity.PayProduct;
import org.xxpay.manage.common.ctrl.BaseController;
import org.xxpay.manage.common.service.RpcCommonService;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

@Controller
@RequestMapping(Constant.MGR_CONTROLLER_ROOT_PATH + "/pay_order")
public class PayOrderController extends BaseController {

    @Autowired
    private RpcCommonService rpcCommonService;

    @Autowired
    private static final MyLog _log = MyLog.getLog(PayOrderController.class);

    /**
     * 查询单条支付记录
     * @return
     */
    @RequestMapping("/get")
    @ResponseBody
    public ResponseEntity<?> get(HttpServletRequest request) {
        JSONObject param = getJsonParam(request);
        String payOrderId = getStringRequired(param, "payOrderId");
        PayOrder payOrder = commonService.payOrderService.findByPayOrderId(payOrderId);
        return ResponseEntity.ok(XxPayResponse.buildSuccess(payOrder));
    }

    /**
     * 支付订单记录列表
     * @return
     */
    @RequestMapping("/list")
    @ResponseBody
    public ResponseEntity<?> list(HttpServletRequest request) {
        JSONObject param = getJsonParam(request);
        Integer page = getInteger(param, "page");
        Integer limit = getInteger(param, "limit");
        PayOrder payOrder = getObject(param, PayOrder.class);
        // 订单起止时间
        Date createTimeStart = null;
        Date createTimeEnd = null;
        String createTimeStartStr = getString(param, "createTimeStart");
        if(StringUtils.isNotBlank(createTimeStartStr)) createTimeStart = DateUtil.str2date(createTimeStartStr);
        String createTimeEndStr = getString(param, "createTimeEnd");
        if(StringUtils.isNotBlank(createTimeEndStr)) createTimeEnd = DateUtil.str2date(createTimeEndStr);

        int count = commonService.payOrderService.count(payOrder, createTimeStart, createTimeEnd);
        if(count == 0) return ResponseEntity.ok(XxPayPageRes.buildSuccess());

        // 支付产品很多时,要考虑内存溢出问题
        List<PayProduct> payProductList = commonService.payProductService.selectAll();
        Map<String, PayProduct> payProductMap = new HashMap<>();
        for(PayProduct product : payProductList) {
            payProductMap.put(String.valueOf(product.getId()), product);
        }
        // 查询商户名称
        Map<String, String> mchNameMap = commonService.mchInfoService.selectNameMap();

        List<PayOrder> payOrderList = commonService.payOrderService.select(
                (getPageIndex(page) -1) * getPageSize(limit), getPageSize(limit), payOrder, createTimeStart, createTimeEnd);
        List<JSONObject> objects = new LinkedList<>();
        for (PayOrder p : payOrderList) {
            JSONObject object = (JSONObject) JSON.toJSON(p);
            if(payProductMap.get(String.valueOf(p.getProductId())) != null) {
                object.put("productName", payProductMap.get(String.valueOf(p.getProductId())).getProductName());
            }
            String mchName = mchNameMap.get(p.getMchId()+"");
            if(StringUtils.isNotEmpty(mchName)) object.put("mchName", mchName);             // 商户名称
            objects.add(object);
        }

        return ResponseEntity.ok(XxPayPageRes.buildSuccess(objects, count));
    }

    /**
     * 查询订单统计数据
     * @return
     */
    @RequestMapping("/count")
    @ResponseBody
    public ResponseEntity<?> count(HttpServletRequest request) {
        JSONObject param = getJsonParam(request);
        String payOrderId = getString(param, "payOrderId");
        String mchOrderNo = getString(param, "mchOrderNo");
        Long productId = getLong(param, "productId");
        Long passageId = getLong(param, "passageId");
        Long passageAccountId = getLong(param, "passageAccountId");
        Long mchId = getLong(param, "mchId");
        Byte productType = getByte(param, "productType");
        String channelMchId = getString(param, "channelMchId");
        String subject = getString(param, "subject");
        Long amount = getLong(param, "amount");
        Byte isReissue = getByte(param, "isReissue");
        // 订单起止时间
        String createTimeStartStr = getString(param, "createTimeStart");
        String createTimeEndStr = getString(param, "createTimeEnd");
        Map allMap = commonService.payOrderService.count4All(null, mchId, productId, passageId, passageAccountId, payOrderId,
                mchOrderNo, productType, channelMchId, subject, amount, null, null, isReissue, createTimeStartStr, createTimeEndStr);

        Map successMap = commonService.payOrderService.count4Success(null, mchId, productId, passageId, passageAccountId, payOrderId,
                mchOrderNo, productType, channelMchId, subject, amount, null, null, isReissue, createTimeStartStr, createTimeEndStr);

        Map failMap = commonService.payOrderService.count4Fail(null, mchId, productId, passageId, passageAccountId, payOrderId,
                mchOrderNo, productType, channelMchId, subject, amount, null, null, isReissue, createTimeStartStr, createTimeEndStr);

        JSONObject obj = new JSONObject();
        obj.put("allTotalCount", allMap.get("totalCount"));                         // 所有订单数
        obj.put("allTotalAmount", allMap.get("totalAmount"));                       // 总金额
        obj.put("successTotalCount", successMap.get("totalCount"));                 // 成功订单数
        obj.put("successTotalAmount", successMap.get("totalAmount"));               // 成功金额
        obj.put("successTotalMchIncome", successMap.get("totalMchIncome"));         // 成功商户收入
        obj.put("successTotalAgentProfit", successMap.get("totalAgentProfit"));     // 成功代理商利润
        obj.put("successTotalParentAgentProfit", successMap.get("totalParentAgentProfit"));     // 成功总代理利润
        obj.put("successTotalPlatProfit", successMap.get("totalPlatProfit"));       // 成功平台利润
        obj.put("successTotalChannelCost", successMap.get("totalChannelCost"));     // 成功平台成本
        obj.put("failTotalCount", failMap.get("totalCount"));                       // 未完成订单数
        obj.put("failTotalAmount", failMap.get("totalAmount"));                     // 未完成金额
        return ResponseEntity.ok(XxPayResponse.buildSuccess(obj));
    }

    /**
     * 补单
     * 1. 将订单为 支付中 状态的修改为支付成功
     * 2. 给商户下发一次通知
     * @return
     */
    @RequestMapping("/reissue")
    @ResponseBody
    @MethodLog( remark = "补单" )
    public ResponseEntity<?> reissue(HttpServletRequest request) {
        JSONObject param = getJsonParam(request);

        // 判断输入的超级密码是否正确
        String password = getStringRequired(param, "password");
        if(!checkMgrSuperPwd(password)) {
            return ResponseEntity.ok(BizResponse.build(RetEnum.RET_MGR_SUPER_PASSWORD_NOT_MATCH));
        }
        // 是否通知商户
        boolean isNotifyMch = false;
        // 修改订单状态
        String payOrderId = getStringRequired(param, "payOrderId");
        String remark = getString(param, "remark");
        handleParamAmount(param, "realAmount");
        Long realAmount = getLong(param, "realAmount");

        PayOrder payOrderOld = commonService.payOrderService.findByPayOrderId(payOrderId);
        Long diffAmount = 0L;
        if (realAmount != null) {
            diffAmount = realAmount - payOrderOld.getAmount();
        }

        int updateCount = commonService.payOrderService.reissueOrder(payOrderId, getUser().getId(), realAmount, remark, MchConstant.SYSTYPE_MGR);

        if(updateCount == 1) {
            isNotifyMch = true;
        }

        // 发送商户通知
        if(isNotifyMch) {
            //发送订单成功统计通知
            rpcCommonService.rpcXxPayNotifyService.sendPayStatistics(payOrderId, diffAmount);

            rpcCommonService.rpcXxPayNotifyService.executePayNotify(payOrderId);

            PayOrder payOrder = commonService.payOrderService.findByPayOrderId(payOrderId);
            try {

                //如果为直付通接口， 需要调用结算接口
                if( PayConstant.CHANNEL_NAME_ALIZFTPAY.equals( payOrder.getChannelType())){
                    rpcCommonService.rpcXxPayPayService.alizftTradeSettleConfirm(payOrder.getChannelOrderNo(), payOrderId);
                }

            } catch (Exception e) {
                _log.error("调起直付通结算失败！", e);
            }
        }

        return ResponseEntity.ok(XxPayResponse.buildSuccess());
    }

    /**
     * 手动模拟商户回调（向商户通知地址发起支付回调,不会修改支付订单状态）
     * @return
     */
    @RequestMapping("/manual")
    @ResponseBody
    public ResponseEntity<?> manual(HttpServletRequest request) {
        JSONObject param = getJsonParam(request);
        String notifyOrderId = getStringRequired(param, "notifyOrderId");
        String notifyOrderType = getStringRequired(param, "notifyOrderType");
        String notifyUrl = param.getString("notifyUrl");
        PayOrder payOrder = null;
        if ("1".equals(notifyOrderType)) {
            payOrder = commonService.payOrderService.findByPayOrderId(notifyOrderId);
        }else if ("2".equals(notifyOrderType)) {
            payOrder = commonService.payOrderService.findByMchOrderNo(notifyOrderId);
        }else {
            return ResponseEntity.ok(BizResponse.build(RetEnum.RET_MCH_PAY_NOTIFY_ORDERID_ERROR));
        }
        if (payOrder == null) return ResponseEntity.ok(BizResponse.build(RetEnum.RET_MCH_TRADE_ORDER_NOT_EXIST));
        // 当前系统时间
        long startTime =  System.currentTimeMillis();
        // 发送回调通知
        JSONObject json = rpcCommonService.rpcXxPayNotifyService.manualPayNotify(payOrder, notifyUrl);
        // 计算耗时
        long endTime =  System.currentTimeMillis();
        long usedTime = (endTime-startTime);
        if ("success".equals(json.getString("result"))) {
            json.put("request", "请求成功！");
        }else {
            json.put("request", "请求失败！");
        }
        json.put("usedTime", usedTime);
        return ResponseEntity.ok(XxPayResponse.buildSuccess(json));
    }

    /** 查询上游状态 **/
    @RequestMapping("/queryChannel")
    @ResponseBody
    public ResponseEntity<?> queryChannel(HttpServletRequest request) {
        JSONObject param = getJsonParam(request);

        // 判断输入的超级密码是否正确
        String password = getStringRequired(param, "password");
        if(!checkMgrSuperPwd(password)) {
            return ResponseEntity.ok(BizResponse.build(RetEnum.RET_MGR_SUPER_PASSWORD_NOT_MATCH));
        }

        String payOrderId = getStringRequired(param, "payOrderId");
        QueryRetMsg queryRetMsg = rpcCommonService.rpcXxPayPayService.queryChannelStatus(payOrderId);

        String channelStatus = "未知"; //渠道状态

        if(queryRetMsg.getChannelState() == QueryRetMsg.ChannelState.CONFIRM_SUCCESS){
            channelStatus = "[支付成功]";
        }else if(queryRetMsg.getChannelState() == QueryRetMsg.ChannelState.CONFIRM_FAIL){
            channelStatus = "[支付成功]";
        }else if(queryRetMsg.getChannelState() == QueryRetMsg.ChannelState.SYS_ERROR){
            channelStatus = "[系统异常]";
        }else if(queryRetMsg.getChannelState() == QueryRetMsg.ChannelState.UNKNOWN){
            channelStatus = "[未知]";
        }else if(queryRetMsg.getChannelState() == QueryRetMsg.ChannelState.WAITING){
            channelStatus = "[支付中]";
        }
        return ResponseEntity.ok(XxPayResponse.buildSuccess(channelStatus));
    }


    @RequestMapping("/exportExcel")
    @ResponseBody
    public String exportExcel(HttpServletRequest request) throws Exception {

        JSONObject param = getJsonParam(request);
        PayOrder payOrder = getObject(param, PayOrder.class);
        // 订单起止时间
        Date createTimeStart = null;
        Date createTimeEnd = null;
        String createTimeStartStr = getString(param, "createTimeStart");
        if(StringUtils.isNotBlank(createTimeStartStr)) createTimeStart = DateUtil.str2date(createTimeStartStr);
        String createTimeEndStr = getString(param, "createTimeEnd");
        if(StringUtils.isNotBlank(createTimeEndStr)) createTimeEnd = DateUtil.str2date(createTimeEndStr);
        int count = commonService.payOrderService.count(payOrder, createTimeStart, createTimeEnd);
        if(count > MchConstant.MAX_EXPORT_ROW) return RetEnum.RET_SERVICE_OUT_OF_RANGE_MAX_EXPORT_ROW.getMessage();

        int pageIndex = 1;
        int limit = 200;
        boolean flag = true;
        List<List> excelData = new ArrayList<>();
        List header = Arrays.asList(new String[]{"商户ID", "商户订单", "支付单号", "支付金额", "产品类型", "状态", "创建时间"});
        excelData.add(header);
        // 循环查询所有
        while (flag) {
            List<PayOrder> payOrderList = commonService.payOrderService.select((pageIndex - 1) * limit, limit, payOrder, createTimeStart, createTimeEnd);
            for(PayOrder record : payOrderList){
                List rowData = new ArrayList<>();
                rowData.add(record.getMchId());
                rowData.add(record.getMchOrderNo());
                rowData.add(record.getPayOrderId());
                rowData.add(AmountUtil.convertCent2Dollar(record.getAmount()+""));
                switch (record.getProductType()){
                    case MchConstant.PRODUCT_TYPE_PAY : rowData.add("收款"); break;
                    case MchConstant.PRODUCT_TYPE_RECHARGE : rowData.add("充值"); break;
                    default: rowData.add("未知"); break;
                }
                switch (record.getStatus()){
                    case PayConstant.PAY_STATUS_INIT: rowData.add("订单初始"); break;
                    case PayConstant.PAY_STATUS_PAYING: rowData.add("支付中"); break;
                    case PayConstant.PAY_STATUS_SUCCESS: rowData.add("支付成功"); break;
                    case PayConstant.PAY_STATUS_REFUND: rowData.add("已退款"); break;
                    case PayConstant.PAY_STATUS_COMPLETE: rowData.add("业务完成"); break;
                    case PayConstant.PAY_STATUS_CLOSED: rowData.add("订单关闭"); break;
                    default: rowData.add("未知"); break;
                }
                rowData.add(DateUtil.date2Str(record.getCreateTime()));
                excelData.add(rowData);
            }

            pageIndex++;
            if(CollectionUtils.isEmpty(payOrderList) || payOrderList.size() < limit) {
                flag = false;
            }
        }
        super.writeExcelStream("支付订单", excelData);
        return null;
    }


}